package cn.org.xwb.common.redis.utils;

import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Component
@Log4j2
public class RedisUtil {

    @Autowired
    private RedisTemplate redisTemplate;

    public Object getAndDel(String key) {
        return redisTemplate.opsForValue().getAndDelete(key);
    }

    /**
     * 获取并重置有效时间
     *
     * @param key
     * @param expire
     * @param expireUnit
     * @return
     */
    public Object getAndResetExpire(String key, Long expire, TimeUnit expireUnit) {
        return redisTemplate.opsForValue().getAndExpire(key, expire, expireUnit);
    }

    /**
     * 判断指定的键值是否存在
     *
     * @param key
     * @return
     */
    public Boolean contain(String key) {
        Object obj = redisTemplate.opsForValue().get(key);
        return Objects.nonNull(obj);
    }

    /**
     * 向 redis 中保存 value 值
     *
     * @param key 键
     * @param value 字符串类型的 value 值
     * @param expire 键值对的有效时间，为 null，则永久有效
     * @param expireUnit 有效时间的单位，默认秒
     */
    public boolean setVal(String key, Object value, Long expire, TimeUnit expireUnit) {
        try {
            ValueOperations valueOperations = redisTemplate.opsForValue();
            if (Objects.isNull(expire)) {
                valueOperations.set(key, value);
            }
            if (!Objects.isNull(expire) && Objects.isNull(expireUnit)) {
                valueOperations.set(key, value, expire, TimeUnit.SECONDS);
            }
            if (!Objects.isNull(expire) && !Objects.isNull(expireUnit)) {
                valueOperations.set(key, value, expire, expireUnit);
            }
            log.info("向 redis 中保存字符串类型的 value 值成功，key；{}", key);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            log.error("向 redis 中保存字符串类型的 value 值失败，key；{}，value：{}", key, value);
            return false;
        }

    }

    /**
     * 向 redis 中保存字符串类型的 value 值
     *
     * @param key 键
     * @param value 字符串类型的 value 值
     * @param expire 键值对的有效时间，为 null，则永久有效，
     *               有效时间单位默认为秒
     */
    public boolean setVal(String key, Object value, Long expire) {
        return setVal(key, value, expire, null);
    }

    /**
     * 向 redis 中保存字符串类型的 value 值，
     * 默认键值对永久有效
     *
     * @param key 键
     * @param value 字符串类型的 value 值
     */
    public boolean setVal(String key, Object value) {
        return setVal(key, value, null, null);
    }


    /**
     * 获取字符串形式的 value
     *
     * @param key
     * @return
     */
    public String getStr(String key) {
        Object obj = redisTemplate.opsForValue().get(key);
        if (Objects.nonNull(obj)) return (String) obj;
        return null;
    }

    /**
     * 保存 list
     *
     * @param key
     * @param list
     * @return
     */
    public Boolean setList(String key, Object list) {
        try {
            redisTemplate.opsForValue().set(key, list);
            return true;
        } catch (Exception e) {
            // e.printStackTrace();
            return false;
        }
    }

    public Object get(String key) {
        return redisTemplate.opsForValue().get(key);
    }

    /**
     * 判断对象是否包含在 redis 中的 list 中
     *
     * @param key
     * @param obj
     * @return
     */
    public Boolean objContainInList(String key, Object obj) {
        Long objIdx = redisTemplate.opsForList().indexOf(key, obj);
        return Objects.nonNull(objIdx);
    }

    /**
     * 判断在 redis 中的 list 中是否包含指定的 item
     *
     * @param key
     * @param listItemHandler 对 redis 中的 list 中的 item 处理
     * @return
     */
    public Boolean objContainInList(String key, ListItemHandler listItemHandler) {
        List<Object> objectList = (List<Object>) redisTemplate.opsForValue().get(key);
        for (Object item : objectList) {
            if (((Boolean) listItemHandler.handlerListItem(item))) {
                return true;
            }
        }
        return false;
    }

    /**
     * 函数式接口，对 redis 中的 list 中的 item 处理
     */
    @FunctionalInterface
    public interface ListItemHandler {
        Object handlerListItem(Object item);
    }

}
